package de.latzko.pattern.monteCarlo

import java.util.Random
import java.util.Random._
import de.latzko.pattern.math._
import de.latzko.pattern.math.NearestNeighbour
import scalala.tensor.dense.DenseVector._
import scalala.tensor.dense.DenseVector
import scalala.Scalala._
import scalala.Scalala
import scala.actors._
import Actor._

class SuperParaMagnetic(vectors: Array[DenseVector], q: Int, k: Int, var sigma: Double = 0.5) extends Wolff(vectors, q, k) with ScatterPlot {
  var deltaIj = new Array[Int]((n * (n - 1)) / 2);
  var label = new Array[Int](n)
  var nDelta: Double = 0;

  def runMethode(mcSteps: Int, tempSteps: Int = 200, deltaT: Double = 0.0001): Unit = {
    var T: Double = 0;
    T = 0.05
    for (j <- 1 to tempSteps) {
      init()
    	for (i <- 1 to mcSteps) {
        monteCarloStep(T)
      }
      for (i <- 1 to mcSteps) {
        monteCarloStep(T)
        deltas()
      }
      labelLabel();
      reduceLabel()

    }
  }

  def deltas(): Unit = {
    for (i <- 0 until n; j <- i + 1 until n) {
      if (spins(i) == spins(j))
        deltaIj(i + (j * (j - 1) / 2)) += 1
    }
    nDelta += 1
  }

  def labelLabel(): Unit = {
    val cutoff =  sigma * nDelta // cutoff criterium
    var newLabel = 1
    for (i <- 0 until n - 1) {
      if (label(i) == 0) {
        val connected = growLabel(i, newLabel,cutoff);
        if (connected)
          newLabel += 1;
        else
          label(i) = 0

      }
    }
  }

  def growLabel(i: Int, newLabel: Int,cutoff:Double): Boolean = {
    var connected = false;
    if (label(i) == 0) {
      label(i) = newLabel
      for (j <- i + 1 until n) {

        if (getDeltaIj(i, j) > cutoff) {
            if (label(j) == 0) 
            	growLabel(j, newLabel,cutoff);
          connected = true
        }
      }
    }
    return connected
  }


  val getDeltaIj = (i: Int, j: Int) => deltaIj(i + (j * (j - 1)) / 2)
 
  def reduceLabel() = {
	val maxLabel = label.reduceRight(_ max _)
    var arr = new Array[Int](maxLabel+ 1)
    label.foreach(x => arr(x) += 1)
    val fivePercent = 0.05*n
    for(i<-1 to maxLabel){
    	if(arr(i)< fivePercent)
    		label = label.map(x=> if(x!= i) x else 0)
    }
  }
  override def init():Unit = {
	  super.init()
	  deltaIj = deltaIj.map(x=>0)
	  label = label .map(x=>0)
	  nDelta = 0
  }
  
}